package edu.cicese.alz.reports;

import edu.cicese.alz.DataUtil;
import edu.cicese.alz.FrameReport;
import edu.cicese.alz.TimeUtil;
import edu.cicese.alz.swing.CustomButton;
import edu.cicese.alz.swing.DynamicCardLayout;
import edu.cicese.alz.swing.IntegerDocumentFilter;
import edu.cicese.alz.swing.JColorButton;
import edu.cicese.alz.swing.JNonEmptyTextField;
import edu.cicese.alz.swing.MapPreview;
import edu.cicese.alz.swing.SwingUtil;
import edu.cicese.alz.swing.calendar.DateChooser;
import edu.cicese.alz.swing.calendar.TextFieldDateEditor;
import edu.cicese.alz.util.PropertyUtil;

import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.PlainDocument;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.TreeSet;

/**
 * Created by: Eduardo Quintana Contreras
 * Date: 3/07/12
 * Time: 12:07 PM
 */
public class GPSPane extends ReportPane {
	private Box boxGPS;

	// Type
	private JToggleButton btnTypeBlock, btnTypeMap;

	// Period
	private TextFieldDateEditor txtPeriodFrom, txtPeriodTo;
	private DateChooser dChooserFrom, dChooserTo;
	private JRadioButton rbtPeriodAll, rbtPeriodFrom;
	private JSpinner sIntervalFrom, sIntervalTo;
	private JCheckBox chbDailyMap;
	private JPanel pDailyMap;

	// Block colors
	private JButton btnBlockNoDataColor, btnBlockHomeColor, btnBlockOutColor;

	// Block preview
	private BlockGPSPreview pGPSPreview;

	// Home radius
	private PlainDocument txtHomeRadiusModel = new PlainDocument();
	private JNonEmptyTextField txtBlockHomeRadius;
	private JNonEmptyTextField txtMapHomeRadius;

	// Map visualization
	private JCheckBox chbMapShowMarkers, chbMapShowLocations, chbMapShowTracks, chbMapShowLabels, chbMapShowGrid;
	private JCheckBox chbMapShowZoomControl, chbMapShowMarkerControl;
	private JComboBox cmbMapLayer;
	private MapPreview pMapPreview;

	// Track
	private JColorButton btnMapTrackColor;
	private JSlider jsMapTrackOpacity, jsMapTrackThickness;

	// Marker
	private JColorButton btnMapMarkerColor, btnMapMarkerBorderColor;
	private JSlider jsMapMarkerOpacity;

	// Location
	private JColorButton btnMapLocationColor, btnMapLocationBorderColor;
	private JPanel pLocationMerge;
	private JNonEmptyTextField txtMapLocationRadius, txtMapLocationMinTime, txtMapLocationMergeRadius;
	private JCheckBox chbMapLocationMerge;
	private JCheckBox chbMapShowLocationInfo;
	private JComboBox cmbMapLocationInfoType;
	private JCheckBox chbMapAdjustLocationSize;
	private JSlider jsMapLocationOpacity, jsMapLocationSize;

	// Label
	private JCheckBox chbMapLabelDay, chbMapLabelHour, chbMapLabelDistance, chbMapLabelTime, chbMapLabelSpeed;
	private JLabel lblMapLabelPreview;
	private String[] example = new String[]{"16/01/2012", "09:14:42", "300m", "60s", "5m/s"};

	public GPSPane() {
		initComponents();
		initOptionScrollPane(boxGPS);
		loadOptions();
	}

	private void initComponents() {
		// Type
		btnTypeBlock = SwingUtil.createToggleButton("", "Block", getIcon("gps_block"));
		btnTypeMap = SwingUtil.createToggleButton("", "Map", getIcon("gps_map"));

		Box boxTypes = createHorizontalBox(new Component[]{
				Box.createHorizontalGlue(),
				btnTypeBlock,
				Box.createHorizontalStrut(5),
				btnTypeMap,
				Box.createHorizontalGlue()
		});

		Box boxTypeContent = createVerticalBox(new Component[]{
				boxTypes
		});

		// Users
		Box boxUsersContent = createUsersBox();

		// Period
		rbtPeriodAll = SwingUtil.createRadioButton("All");
		rbtPeriodAll.setModel(FrameReport.rbtPeriodAllModel);
		rbtPeriodFrom = SwingUtil.createRadioButton("From:");
		rbtPeriodFrom.setModel(FrameReport.rbtPeriodFromModel);
		ButtonGroup rgPeriod = new ButtonGroup();
		rgPeriod.add(rbtPeriodAll);
		rgPeriod.add(rbtPeriodFrom);


		txtPeriodFrom = new TextFieldDateEditor();
		txtPeriodFrom.setDocument(FrameReport.txtDayFromModel);

		txtPeriodTo = new TextFieldDateEditor();
		txtPeriodTo.setDocument(FrameReport.txtDayToModel);

		txtPeriodFrom.getDocument().addDocumentListener(new DateDocumentListener(txtPeriodFrom, txtPeriodTo));
		dChooserFrom = new DateChooser(new Date(), "dd-MM-yyyy", txtPeriodFrom);

		txtPeriodTo.getDocument().addDocumentListener(new DateDocumentListener(txtPeriodFrom, txtPeriodTo));
		dChooserTo = new DateChooser(new Date(), "dd-MM-yyyy", txtPeriodTo);

		Box boxDays = createHorizontalBox(new Component[]{
				rbtPeriodFrom,
				Box.createHorizontalStrut(5),
				dChooserFrom,
				Box.createHorizontalStrut(3),
				new JLabel("to:"),
				Box.createHorizontalStrut(5),
				dChooserTo,
		});

		sIntervalFrom = SwingUtil.createSpinner(new Date(), FrameReport.sHourFromModel);
		sIntervalTo = SwingUtil.createSpinner(new Date(), FrameReport.sHourToModel);

		Box boxInterval = createHorizontalBox(new Component[]{
				new JLabel("From:"),
				Box.createHorizontalStrut(5),
				sIntervalFrom,
				Box.createHorizontalStrut(5),
				new JLabel("to:"),
				Box.createHorizontalStrut(5),
				sIntervalTo
		});

		chbDailyMap = SwingUtil.createCheckBox("Create daily maps");

		Box boxDailyMap = createHorizontalBox(new Component[]{
				chbDailyMap
		});

		pDailyMap = createCardPane();
		pDailyMap.add("daily", boxDailyMap);
		pDailyMap.add("empty", createEmptyPane());

		Box boxPeriod1 = createVerticalBox(new Component[]{
				rbtPeriodAll,
				boxDays
		});

		Box boxPeriod2 = createVerticalBox(new Component[]{
				boxInterval,
				Box.createVerticalStrut(2),
				pDailyMap
		});

		JPanel pPeriod = createContentPane(new Box[]{
				boxPeriod1,
				boxPeriod2
		});

		// Saving options
		Box boxSavingContent = createSavingBox();

		// Advanced

		// BLOCK

		// Home radius
		txtBlockHomeRadius = SwingUtil.createNonEmptyTextField(25, 20);
		txtBlockHomeRadius.setDocument(txtHomeRadiusModel);

		Box boxBlockHomeRadius = createHorizontalBox(new Component[]{
				new JLabel("Home radius:"),
				Box.createHorizontalStrut(5),
				txtBlockHomeRadius,
				Box.createHorizontalStrut(2),
				new JLabel("m.")
		});

		// Colors
		btnBlockNoDataColor = SwingUtil.createColorButton(20, 20);
		btnBlockNoDataColor.addPropertyChangeListener(new BlockColorChangeListener());
		btnBlockHomeColor = SwingUtil.createColorButton(20, 20);
		btnBlockHomeColor.addPropertyChangeListener(new BlockColorChangeListener());
		btnBlockOutColor = SwingUtil.createColorButton(20, 20);
		btnBlockOutColor.addPropertyChangeListener(new BlockColorChangeListener());

		pGPSPreview = new BlockGPSPreview();
		CustomButton btnReloadPreview = SwingUtil.createCustomButton("", "Reload preview", getIcon("b_refresh"), Color.WHITE);
		btnReloadPreview.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionReloadPreview();
			}
		});

		Box boxBlockPreview1 = createVerticalBox(new Component[]{
				boxBlockHomeRadius,
				Box.createVerticalStrut(2),
				createHorizontalColorBox(btnBlockNoDataColor, "No Data"),
				Box.createVerticalStrut(2),
				createHorizontalColorBox(btnBlockHomeColor, "Home"),
				Box.createVerticalStrut(2),
				createHorizontalColorBox(btnBlockOutColor, "Out")
		});

		Box boxBlockPreview2a = createVerticalBox(new Component[]{
				pGPSPreview
		}, 0);

		Box boxBlockPreview2b = createVerticalBox(new Component[]{
				btnReloadPreview
		}, 3);

		JPanel pBlockPreview2 = createContentPane(new Box[]{
				boxBlockPreview2a, boxBlockPreview2b
		});

		Box boxBlockPreview2 = createVerticalBox(new Component[]{
				createTitlePane("Preview", SwingUtil.cBackground),
				Box.createVerticalStrut(4),
				pBlockPreview2
		}, 10);

		JPanel pBlockPreview = createContentPane(new Box[]{
				boxBlockPreview1, boxBlockPreview2
		});


		// MAP

		// Home radius

		txtMapHomeRadius = SwingUtil.createNonEmptyTextField(25, 20);
		txtMapHomeRadius.setDocument(txtHomeRadiusModel);

		txtMapHomeRadius.getDocument().addDocumentListener(new EmptyTextListener(txtMapHomeRadius));
		((AbstractDocument) txtMapHomeRadius.getDocument()).setDocumentFilter(new IntegerDocumentFilter(txtMapHomeRadius));
		txtBlockHomeRadius.getDocument().addDocumentListener(new EmptyTextListener(txtBlockHomeRadius));
		((AbstractDocument) txtBlockHomeRadius.getDocument()).setDocumentFilter(new IntegerDocumentFilter(txtBlockHomeRadius));
		Box boxMapHomeRadius = createHorizontalBox(new Component[]{
				new JLabel("Home radius:"),
				Box.createHorizontalStrut(5),
				txtMapHomeRadius,
				Box.createHorizontalStrut(2),
				SwingUtil.createLabel("m.", 190, 20)
		});

		// Map layer
		cmbMapLayer = SwingUtil.createComboBox(new String[]{"Map", "Satellite"}, 85, 20);
		cmbMapLayer.addActionListener(new MapLayerActionListener());
		Box boxMapLayer = createHorizontalBox(new Component[]{
				new JLabel("Layer:"),
				Box.createHorizontalStrut(5),
				cmbMapLayer
		});

		chbMapShowMarkers = SwingUtil.createCheckBox("Show markers");
		chbMapShowMarkers.addActionListener(new MapShowActionListener(chbMapShowMarkers, MapPreview.MARKERS));
		chbMapShowLocations = SwingUtil.createCheckBox("Show locations");
		chbMapShowLocations.addActionListener(new MapShowActionListener(chbMapShowLocations, MapPreview.LOCATIONS));
		chbMapShowTracks = SwingUtil.createCheckBox("Show tracks");
		chbMapShowTracks.addActionListener(new MapShowActionListener(chbMapShowTracks, MapPreview.TRACKS));
		chbMapShowLabels = SwingUtil.createCheckBox("Show labels");
		chbMapShowLabels.addActionListener(new MapShowActionListener(chbMapShowLabels, MapPreview.LABELS));
		chbMapShowGrid = SwingUtil.createCheckBox("Show grid");
		chbMapShowGrid.addActionListener(new MapShowActionListener(chbMapShowGrid, MapPreview.GRID));
		chbMapShowZoomControl = SwingUtil.createCheckBox("Show zoom control");
		chbMapShowZoomControl.addActionListener(new MapShowActionListener(chbMapShowZoomControl, MapPreview.ZOOM_CONTROL));
		chbMapShowMarkerControl = SwingUtil.createCheckBox("Show marker control");
		chbMapShowMarkerControl.addActionListener(new MapShowActionListener(chbMapShowMarkerControl, MapPreview.MARKER_CONTROL));

		Box boxMapGeneral1 = createVerticalBox(new Component[]{
				boxMapLayer,
				Box.createVerticalStrut(2),
				chbMapShowMarkers,
				Box.createVerticalStrut(2),
				chbMapShowLocations,
				Box.createVerticalStrut(2),
				chbMapShowTracks
		}, 0);

		Box boxMapGeneral2 = createVerticalBox(new Component[]{
				chbMapShowLabels,
				Box.createVerticalStrut(2),
				chbMapShowGrid,
				Box.createVerticalStrut(2),
				chbMapShowZoomControl,
				Box.createVerticalStrut(2),
				chbMapShowMarkerControl
		}, 30);

		JPanel pMapGeneral = createContentPane(new Box[]{
				boxMapGeneral1,
				boxMapGeneral2
		});

		Box boxMapGeneral = createVerticalBox(new Component[]{
				boxMapHomeRadius,
				Box.createVerticalStrut(2),
				pMapGeneral
		});

		// MAP MARKER

		// Marker background
		btnMapMarkerColor = SwingUtil.createColorButton(20, 20);
		btnMapMarkerColor.addPropertyChangeListener(new MapMarkerBackgroundChangeListener());

		// Marker border
		btnMapMarkerBorderColor = SwingUtil.createColorButton(20, 20);
		btnMapMarkerBorderColor.addPropertyChangeListener(new MapMarkerBorderChangeListener());

		jsMapMarkerOpacity = SwingUtil.createSlider(SwingConstants.HORIZONTAL, 0, 255, 0, 120, 20);
		jsMapMarkerOpacity.addChangeListener(new MapMarkerTransparencyChangeListener());
		Box boxMapMarkerTransparency = createHorizontalBox(new Component[]{
				SwingUtil.createLabel("Opacity", 55, 20),
				jsMapMarkerOpacity
		});

		Box boxMapMarker = createVerticalBox(new Component[]{
				createHorizontalColorBox(btnMapMarkerColor, "Marker background"),
				Box.createVerticalStrut(2),
				createHorizontalColorBox(btnMapMarkerBorderColor, "Marker border"),
				Box.createVerticalStrut(2),
				boxMapMarkerTransparency
		});

		// MAP LOCATION

		// Radius
		txtMapLocationRadius = SwingUtil.createNonEmptyTextField(25, 20);
		txtMapLocationRadius.getDocument().addDocumentListener(new LocationEmptyTextListener(txtMapLocationRadius));
		((AbstractDocument) txtMapLocationRadius.getDocument()).setDocumentFilter(new IntegerDocumentFilter(txtMapLocationRadius));
		Box boxMapLocationRadius = createHorizontalBox(new Component[]{
				SwingUtil.createLabel("Radius:", 85, 20),
				txtMapLocationRadius,
				Box.createHorizontalStrut(2),
				new JLabel("m.")
		});

		// Minimum time in location
		txtMapLocationMinTime = SwingUtil.createNonEmptyTextField(25, 20);
		txtMapLocationMinTime.getDocument().addDocumentListener(new LocationEmptyTextListener(txtMapLocationMinTime));
		((AbstractDocument) txtMapLocationMinTime.getDocument()).setDocumentFilter(new IntegerDocumentFilter(txtMapLocationMinTime));
		Box boxMapLocationMinTime = createHorizontalBox(new Component[]{
				SwingUtil.createLabel("Minimum time:", 85, 20),
				txtMapLocationMinTime,
				Box.createHorizontalStrut(2),
				new JLabel("min.")
		});

		// Merging
		chbMapLocationMerge = SwingUtil.createCheckBox("Merge", 52, 20);

		// Merging radius
		txtMapLocationMergeRadius = SwingUtil.createNonEmptyTextField(25, 20);
		txtMapLocationMergeRadius.getDocument().addDocumentListener(new LocationMergeEmptyTextListener(txtMapLocationMergeRadius));
		((AbstractDocument) txtMapLocationMergeRadius.getDocument()).setDocumentFilter(new IntegerDocumentFilter(txtMapLocationMergeRadius));
		Box boxMapLocationMergeRadius = createHorizontalBox(new Component[]{
				new JLabel("(radius:"),
				Box.createHorizontalStrut(2),
				txtMapLocationMergeRadius,
				Box.createHorizontalStrut(2),
				new JLabel("m.)")
		});

		pLocationMerge = createCardPane();
		pLocationMerge.add("merge", boxMapLocationMergeRadius);
		pLocationMerge.add("empty", createEmptyPane());

		Box boxMapLocationMerge = createHorizontalBox(new Component[]{
				chbMapLocationMerge,
				Box.createHorizontalStrut(3),
				pLocationMerge
		});

		chbMapLocationMerge.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				CardLayout cardLayout = (CardLayout) pLocationMerge.getLayout();
				if (chbMapLocationMerge.isSelected()) {
					cardLayout.show(pLocationMerge, "merge");
				} else {
					cardLayout.show(pLocationMerge, "empty");
				}
			}
		});

		// Location background
		btnMapLocationColor = SwingUtil.createColorButton(20, 20);
		btnMapLocationColor.addPropertyChangeListener(new MapLocationBackgroundChangeListener(1));

		// Location border
		btnMapLocationBorderColor = SwingUtil.createColorButton(20, 20);
		btnMapLocationBorderColor.addPropertyChangeListener(new MapLocationBackgroundChangeListener(2));

		// Location transparency
		jsMapLocationOpacity = SwingUtil.createSlider(SwingConstants.HORIZONTAL, 0, 255, 0, 120, 20);
		jsMapLocationOpacity.addChangeListener(new MapLocationTransparencyChangeListener());
		Box boxMapLocationTransparency = createHorizontalBox(new Component[]{
				SwingUtil.createLabel("Opacity", 55, 20),
				jsMapLocationOpacity
		});

		// Location size
		jsMapLocationSize = SwingUtil.createSlider(SwingConstants.HORIZONTAL, 1, 40, 1, 120, 20);
		jsMapLocationSize.addChangeListener(new MapLocationSizeChangeListener());
		Box boxMapLocationSize = createHorizontalBox(new Component[]{
				SwingUtil.createLabel("Size", 55, 20),
				jsMapLocationSize
		});

		// Adjust location size
		chbMapAdjustLocationSize = SwingUtil.createCheckBox("Adjust location size", 135, 20);

		// Location info
		chbMapShowLocationInfo = SwingUtil.createCheckBox("Show location info", 135, 20);
		chbMapShowLocationInfo.addActionListener(new MapShowActionListener(chbMapShowLocationInfo, MapPreview.LOCATION_INFO));

		// Location info type
		cmbMapLocationInfoType = SwingUtil.createComboBox(new String[]{"Incidences", "Time"}, 85, 20);
		cmbMapLocationInfoType.addActionListener(new MapLocationInfoActionListener());
		Box boxMapLocationInfoType = createVerticalBox(new Component[]{
				Box.createVerticalStrut(10),
				cmbMapLocationInfoType
		}, 0);

		Box boxMapLocationAdjustAndInfo = createVerticalBox(new Component[]{
				chbMapAdjustLocationSize,
				Box.createVerticalStrut(2),
				chbMapShowLocationInfo
		}, 0);

		JPanel pMapLocationInfo = createContentPane(new Box[]{
				boxMapLocationAdjustAndInfo,
				boxMapLocationInfoType
		});

		Box boxMapLocation = createVerticalBox(new Component[]{
				boxMapLocationRadius,
				Box.createVerticalStrut(2),
				boxMapLocationMinTime,
				Box.createVerticalStrut(2),
				boxMapLocationMerge,
				Box.createVerticalStrut(2),
				createHorizontalColorBox(btnMapLocationColor, "Location background"),
				Box.createVerticalStrut(2),
				createHorizontalColorBox(btnMapLocationBorderColor, "Location border"),
				Box.createVerticalStrut(2),
				boxMapLocationTransparency,
				Box.createVerticalStrut(2),
				boxMapLocationSize,
				pMapLocationInfo
		});

		// MAP TRACK

		// Track color
		btnMapTrackColor = SwingUtil.createColorButton(20, 20);
		btnMapTrackColor.addPropertyChangeListener(new MapTrackColorChangeListener());

		// Track thickness
		jsMapTrackThickness = SwingUtil.createSlider(SwingConstants.HORIZONTAL, 1, 4, 1, 80, 20);
		jsMapTrackThickness.addChangeListener(new MapTrackThicknessChangeListener());
		Box boxMapTrackerThickness = createHorizontalBox(new Component[]{
				SwingUtil.createLabel("Thickness", 55, 20),
				jsMapTrackThickness
		});

		// Track transparency
		jsMapTrackOpacity = SwingUtil.createSlider(SwingConstants.HORIZONTAL, 0, 255, 0, 120, 20);
		jsMapTrackOpacity.addChangeListener(new MapTrackTransparencyChangeListener());
		Box boxMapTrackTransparency = createHorizontalBox(new Component[]{
				SwingUtil.createLabel("Opacity", 55, 20),
				jsMapTrackOpacity
		});

		Box boxMapTrack = createVerticalBox(new Component[]{
				createHorizontalColorBox(btnMapTrackColor, "Track color"),
				Box.createVerticalStrut(2),
				boxMapTrackerThickness,
				Box.createVerticalStrut(2),
				boxMapTrackTransparency
		});


		// MAP LABEL

		// Options
		chbMapLabelDay = SwingUtil.createCheckBox("Day");
		chbMapLabelDay.addActionListener(new MapShowActionListener(chbMapLabelDay, MapPreview.LABEL_DAY));
		chbMapLabelHour = SwingUtil.createCheckBox("Hour");
		chbMapLabelHour.addActionListener(new MapShowActionListener(chbMapLabelHour, MapPreview.LABEL_HOUR));
		chbMapLabelDistance = SwingUtil.createCheckBox("Distance");
		chbMapLabelDistance.addActionListener(new MapShowActionListener(chbMapLabelDistance, MapPreview.LABEL_DISTANCE));
		chbMapLabelTime = SwingUtil.createCheckBox("Time");
		chbMapLabelTime.addActionListener(new MapShowActionListener(chbMapLabelTime, MapPreview.LABEL_TIME));
		chbMapLabelSpeed = SwingUtil.createCheckBox("Speed");
		chbMapLabelSpeed.addActionListener(new MapShowActionListener(chbMapLabelSpeed, MapPreview.LABEL_SPEED));

		lblMapLabelPreview = new JLabel();
		lblMapLabelPreview.setFont(new Font("Calibri", Font.ITALIC, 12));
		setMapLabelPreviewText();

		Box boxMapLabelShow1 = createVerticalBox(new Component[]{
				chbMapLabelDay,
				Box.createVerticalStrut(2),
				chbMapLabelHour,
				Box.createVerticalStrut(2),
				chbMapLabelDistance
		}, 0);

		Box boxMapLabelShow2 = createVerticalBox(new Component[]{
				chbMapLabelTime,
				Box.createVerticalStrut(2),
				chbMapLabelSpeed
		}, 20);

		JPanel pMapLabelShow = createContentPane(new Box[]{
				boxMapLabelShow1,
				boxMapLabelShow2
		});

		Box boxMapLabel = createVerticalBox(new Component[]{
				new JLabel("Show"),
				Box.createVerticalStrut(2),
				pMapLabelShow,
				Box.createVerticalStrut(2),
				lblMapLabelPreview
		});

		Box boxMap1 = createVerticalBox(new Component[]{
				boxMapGeneral,
				Box.createVerticalStrut(7),
				createTitlePane("Markers", SwingUtil.cReportSubsectionBg),
				Box.createVerticalStrut(7),
				boxMapMarker,
				Box.createVerticalStrut(4),
				createTitlePane("Locations", SwingUtil.cReportSubsectionBg),
				Box.createVerticalStrut(7),
				boxMapLocation,
				Box.createVerticalStrut(4),
				createTitlePane("Tracks", SwingUtil.cReportSubsectionBg),
				Box.createVerticalStrut(7),
				boxMapTrack,
				Box.createVerticalStrut(4),
				createTitlePane("Labels", SwingUtil.cReportSubsectionBg),
				Box.createVerticalStrut(7),
				boxMapLabel,
				Box.createVerticalStrut(4)
		}, 0);

		// Map preview
		pMapPreview = new MapPreview(
				new boolean[]{
						chbMapShowMarkers.isSelected(), chbMapShowLocations.isSelected(), chbMapShowTracks.isSelected(),
						chbMapShowLabels.isSelected(), chbMapShowGrid.isSelected(), chbMapShowZoomControl.isSelected(),
						chbMapShowMarkerControl.isSelected(), chbMapShowLocationInfo.isSelected(),
						chbMapLabelDay.isSelected(), chbMapLabelHour.isSelected(), chbMapLabelDistance.isSelected(),
						chbMapLabelTime.isSelected(), chbMapLabelSpeed.isSelected()},
				cmbMapLayer.getSelectedIndex(),
				// Marker
				btnMapMarkerColor.getBackground(),
				btnMapMarkerBorderColor.getBackground(),
				0,
				// Location
				btnMapLocationColor.getBackground(),
				btnMapLocationBorderColor.getBackground(),
				jsMapLocationOpacity.getValue(),
				jsMapLocationSize.getValue(),
				cmbMapLocationInfoType.getSelectedIndex(),
				// Track
				Color.RED,
				0,
				1,
				400, 517);

		Box boxMap2 = createVerticalBox(new Component[]{
				createTitlePane("Preview", SwingUtil.cBackground),
				Box.createVerticalStrut(4),
				pMapPreview
		});

		JPanel pMap = createContentPane(new Box[]{
				boxMap1,
				boxMap2
		});

		final JPanel pAdvanced = createCardPane(new DynamicCardLayout());
		pAdvanced.add("map", pMap);
		pAdvanced.add("block", pBlockPreview);

		boxGPS = Box.createVerticalBox();

		boxGPS.add(createTitlePane("Chart type"));
		boxGPS.add(Box.createVerticalStrut(7));
		boxGPS.add(boxTypeContent);
		boxGPS.add(Box.createVerticalStrut(7));

		boxGPS.add(createTitlePane("User(s)"));
		boxGPS.add(Box.createVerticalStrut(4));
		boxGPS.add(boxUsersContent);
		boxGPS.add(Box.createVerticalStrut(4));

		boxGPS.add(createTitlePane("Period"));
		boxGPS.add(Box.createVerticalStrut(4));
		boxGPS.add(pPeriod);
		boxGPS.add(Box.createVerticalStrut(4));

		boxGPS.add(createTitlePane("Saving options"));
		boxGPS.add(Box.createVerticalStrut(4));
		boxGPS.add(boxSavingContent);
		boxGPS.add(Box.createVerticalStrut(4));

		boxGPS.add(createTitlePane("Advanced options"));
		boxGPS.add(Box.createVerticalStrut(7));
		boxGPS.add(pAdvanced);
		boxGPS.add(Box.createVerticalStrut(6));

		ButtonGroup btnGroup = new ButtonGroup();
		btnGroup.add(btnTypeBlock);
		btnGroup.add(btnTypeMap);

		btnTypeBlock.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				CardLayout cardLayoutColor = (CardLayout) pAdvanced.getLayout();
				CardLayout cardLayoutDailyMap = (CardLayout) pDailyMap.getLayout();
				if (btnTypeBlock.isSelected()) {
					cardLayoutColor.show(pAdvanced, "block");
					cardLayoutDailyMap.show(pDailyMap, "empty");
					btnTypeMap.setBorder(new EmptyBorder(3, 3, 3, 3));
				} else {
					cardLayoutColor.show(pAdvanced, "map");
					cardLayoutDailyMap.show(pDailyMap, "daily");
					btnTypeMap.setBorder(new LineBorder(SwingUtil.cRolloverBorder, 3));
				}
			}
		});

		btnTypeMap.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				CardLayout cardLayoutColor = (CardLayout) pAdvanced.getLayout();
				CardLayout cardLayoutDailyMap = (CardLayout) pDailyMap.getLayout();
				if (btnTypeMap.isSelected()) {
					cardLayoutColor.show(pAdvanced, "map");
					cardLayoutDailyMap.show(pDailyMap, "daily");
					btnTypeBlock.setBorder(new EmptyBorder(3, 3, 3, 3));
				} else {
					cardLayoutColor.show(pAdvanced, "block");
					cardLayoutDailyMap.show(pDailyMap, "empty");
					btnTypeBlock.setBorder(new LineBorder(SwingUtil.cRolloverBorder, 3));
				}
			}
		});


		loadOptions();
	}


	public void loadOptions() {
		boolean error = false;

		// Type
		if (PropertyUtil.getProperty(PropertyUtil.REP_GPS_TYPE).equals("map")) {
			btnTypeMap.setSelected(true);
		}
		btnTypeBlock.setSelected(!btnTypeMap.isSelected());

		// Users
		try {
			rbtUsersAll.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_USERS_ALL));
			txtUsers.setText(PropertyUtil.getProperty(PropertyUtil.REP_USERS));
		} catch (Exception e) {
			error = true;
		}
		rbtUsers.setSelected(!rbtUsersAll.isSelected());

		// Period
		try {
			rbtPeriodAll.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_PERIOD_ALL));
		} catch (Exception e) {
			error = true;
		}
		rbtPeriodFrom.setSelected(!rbtPeriodAll.isSelected());

		try {
			dChooserFrom.setDate(PropertyUtil.getDate(PropertyUtil.REP_PERIOD_FROM));
			dChooserTo.setDate(PropertyUtil.getDate(PropertyUtil.REP_PERIOD_TO));
		} catch (Exception e) {
			error = true;
		}

		try {
			sIntervalFrom.setValue(TimeUtil.getDate(PropertyUtil.getProperty(PropertyUtil.REP_INTERVAL_FROM)));
			sIntervalTo.setValue(TimeUtil.getDate(PropertyUtil.getProperty(PropertyUtil.REP_INTERVAL_TO)));
		} catch (Exception e) {
			error = true;
		}

		try {
			chbDailyMap.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_DAILY_MAP));
		} catch (Exception e) {
			error = true;
		}

		// Saving options
		try {
			chbSaveCharts.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_SAVE_CHARTS));
			chbShowCharts.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_SHOW_CHARTS));
		} catch (Exception e) {
			error = true;
		}

		// Advanced options
		try {
			txtMapHomeRadius.setText(PropertyUtil.getProperty(PropertyUtil.REP_GPS_HOME_RADIUS));
		} catch (Exception e) {
			error = true;
		}

		// BLOCK
		try {
			btnBlockNoDataColor.setBackground(PropertyUtil.getColor(PropertyUtil.REP_GPS_BLOCK_COLOR_NO_DATA));
			btnBlockHomeColor.setBackground(PropertyUtil.getColor(PropertyUtil.REP_GPS_BLOCK_COLOR_HOME));
			btnBlockOutColor.setBackground(PropertyUtil.getColor(PropertyUtil.REP_GPS_BLOCK_COLOR_OUT));
		} catch (Exception e) {
			error = true;
		}

		// MAP
		try {
			cmbMapLayer.setSelectedItem(PropertyUtil.getProperty(PropertyUtil.REP_GPS_MAP_LAYER));
		} catch (Exception e) {
			error = true;
		}

		try {
			chbMapShowMarkers.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_SHOW_MARKERS));
			chbMapShowLocations.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_SHOW_LOCATIONS));
			chbMapShowTracks.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_SHOW_TRACKS));
			chbMapShowLabels.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_SHOW_LABELS));
			chbMapShowGrid.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_SHOW_GRID));
			chbMapShowZoomControl.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_SHOW_ZOOM_CONTROL));
			chbMapShowMarkerControl.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_SHOW_MARKER_CONTROL));
		} catch (Exception e) {
			error = true;
		}

		// markers
		try {
			btnMapMarkerColor.setBackground(PropertyUtil.getColor(PropertyUtil.REP_GPS_MAP_COLOR_MARKER_BACKGROUND));
			btnMapMarkerBorderColor.setBackground(PropertyUtil.getColor(PropertyUtil.REP_GPS_MAP_COLOR_MARKER_BORDER));
			jsMapMarkerOpacity.setValue(PropertyUtil.getInt(PropertyUtil.REP_GPS_MAP_MARKER_OPACITY));
		} catch (Exception e) {
			error = true;
		}

		// locations
		try {
			txtMapLocationRadius.setText(PropertyUtil.getProperty(PropertyUtil.REP_GPS_MAP_LOCATION_RADIUS));
			txtMapLocationMinTime.setText(PropertyUtil.getProperty(PropertyUtil.REP_GPS_MAP_LOCATION_MIN_TIME));
			chbMapLocationMerge.setSelected(Boolean.valueOf(PropertyUtil.getProperty(PropertyUtil.REP_GPS_MAP_LOCATION_MERGE)));
			txtMapLocationMergeRadius.setText(PropertyUtil.getProperty(PropertyUtil.REP_GPS_MAP_LOCATION_MERGE_RADIUS));
			btnMapLocationColor.setBackground(PropertyUtil.getColor(PropertyUtil.REP_GPS_MAP_COLOR_LOCATION_BACKGROUND));
			btnMapLocationBorderColor.setBackground(PropertyUtil.getColor(PropertyUtil.REP_GPS_MAP_COLOR_LOCATION_BORDER));
			jsMapLocationOpacity.setValue(PropertyUtil.getInt(PropertyUtil.REP_GPS_MAP_LOCATION_OPACITY));
			jsMapLocationSize.setValue(PropertyUtil.getInt(PropertyUtil.REP_GPS_MAP_LOCATION_SIZE));
			cmbMapLocationInfoType.setSelectedItem(PropertyUtil.getProperty(PropertyUtil.REP_GPS_MAP_LOCATION_INFO_TYPE));
			chbMapShowLocationInfo.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_SHOW_LOCATION_INFO));
			chbMapAdjustLocationSize.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_ADJUST_SIZE));
		} catch (Exception e) {
			error = true;
		}

		// tracks
		try {
			btnMapTrackColor.setBackground(PropertyUtil.getColor(PropertyUtil.REP_GPS_MAP_COLOR_TRACK));
			jsMapTrackThickness.setValue(PropertyUtil.getInt(PropertyUtil.REP_GPS_MAP_TRACK_THICKNESS));
			jsMapTrackOpacity.setValue(PropertyUtil.getInt(PropertyUtil.REP_GPS_MAP_TRACK_OPACITY));
		} catch (Exception e) {
			error = true;
		}

		// labels
		try {
			chbMapLabelDay.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_DAY));
			chbMapLabelHour.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_HOUR));
			chbMapLabelDistance.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_DISTANCE));
			chbMapLabelTime.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_TIME));
			chbMapLabelSpeed.setSelected(PropertyUtil.getBoolean(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_SPEED));
		} catch (Exception e) {
			error = true;
		}

		// map preview
		pMapPreview.setLayerType(cmbMapLayer.getSelectedIndex());
		pMapPreview.setMarkerBackground(btnMapMarkerColor.getBackground());
		pMapPreview.setMarkerBorderColor(btnMapMarkerBorderColor.getBackground());
		pMapPreview.setLocationBackground(btnMapLocationColor.getBackground());
		pMapPreview.setLocationBorderColor(btnMapLocationBorderColor.getBackground());
		pMapPreview.setLocationTransparency(jsMapLocationOpacity.getValue());
		pMapPreview.setLocationSize(jsMapLocationSize.getValue());
		pMapPreview.setLocationInfoType(cmbMapLocationInfoType.getSelectedIndex());
		pMapPreview.setShow(new boolean[]{
				chbMapShowMarkers.isSelected(), chbMapShowLocations.isSelected(), chbMapShowTracks.isSelected(),
				chbMapShowLabels.isSelected(), chbMapShowGrid.isSelected(), chbMapShowZoomControl.isSelected(),
				chbMapShowMarkerControl.isSelected(), chbMapShowLocationInfo.isSelected(),
				chbMapLabelDay.isSelected(), chbMapLabelHour.isSelected(), chbMapLabelDistance.isSelected(),
				chbMapLabelTime.isSelected(), chbMapLabelSpeed.isSelected()});
		try {
			pMapPreview.setMarkerTransparency(PropertyUtil.getInt(PropertyUtil.REP_GPS_MAP_MARKER_OPACITY));
			pMapPreview.setTrackColor(PropertyUtil.getColor(PropertyUtil.REP_GPS_MAP_COLOR_TRACK));
			pMapPreview.setTrackThickness(PropertyUtil.getInt(PropertyUtil.REP_GPS_MAP_TRACK_THICKNESS));
			pMapPreview.setTrackTransparency(PropertyUtil.getInt(PropertyUtil.REP_GPS_MAP_TRACK_OPACITY));
		} catch (Exception e) {
			error = true;
		}

		setMapLabelPreviewText();

		if (error) {
			System.out.println("An error occurred loading saved options.");
			loadDefaultOptions();
		}
	}

	public void saveOptions() {
		// Type
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_TYPE, btnTypeBlock.isSelected() ? "block" : "map");

		// Users
		PropertyUtil.setProperty(PropertyUtil.REP_USERS_ALL, String.valueOf(rbtUsersAll.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_USERS, txtUsers.getText());

		// Period
		PropertyUtil.setProperty(PropertyUtil.REP_PERIOD_ALL, String.valueOf(rbtPeriodAll.isSelected()));
		if (!txtPeriodFrom.hasDateError() || !txtPeriodFrom.hasFormatError()) {
			PropertyUtil.setProperty(PropertyUtil.REP_PERIOD_FROM, SwingUtil.calendarDateFormat.format(dChooserFrom.getDate()));
		}
		if (!txtPeriodTo.hasDateError() || !txtPeriodTo.hasFormatError()) {
			PropertyUtil.setProperty(PropertyUtil.REP_PERIOD_TO, SwingUtil.calendarDateFormat.format(dChooserTo.getDate()));
		}
		PropertyUtil.setProperty(PropertyUtil.REP_INTERVAL_FROM, SwingUtil.timeFormat.format(sIntervalFrom.getValue()));
		PropertyUtil.setProperty(PropertyUtil.REP_INTERVAL_TO, SwingUtil.timeFormat.format(sIntervalTo.getValue()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_DAILY_MAP, String.valueOf(chbDailyMap.isSelected()));

		// Saving options
		PropertyUtil.setProperty(PropertyUtil.REP_SHOW_CHARTS, String.valueOf(chbShowCharts.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_SAVE_CHARTS, String.valueOf(chbSaveCharts.isSelected()));

		// Advanced options
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_HOME_RADIUS, txtBlockHomeRadius.getText());

		// MAP
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LAYER, String.valueOf(cmbMapLayer.getSelectedItem()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_MARKERS, String.valueOf(chbMapShowMarkers.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_LOCATIONS, String.valueOf(chbMapShowLocations.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_TRACKS, String.valueOf(chbMapShowTracks.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_LABELS, String.valueOf(chbMapShowLabels.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_GRID, String.valueOf(chbMapShowGrid.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_ZOOM_CONTROL, String.valueOf(chbMapShowZoomControl.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_MARKER_CONTROL, String.valueOf(chbMapShowMarkerControl.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_LOCATION_INFO, String.valueOf(chbMapShowLocationInfo.isSelected()));

		// markers
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_COLOR_MARKER_BACKGROUND, String.valueOf(btnMapMarkerColor.getBackground().getRGB()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_COLOR_MARKER_BORDER, String.valueOf(btnMapMarkerBorderColor.getBackground().getRGB()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_MARKER_OPACITY, String.valueOf(jsMapMarkerOpacity.getValue()));

		// locations
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LOCATION_RADIUS, txtMapLocationRadius.getText());
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LOCATION_MIN_TIME, txtMapLocationMinTime.getText());
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LOCATION_MERGE, String.valueOf(chbMapLocationMerge.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LOCATION_MERGE_RADIUS, txtMapLocationMergeRadius.getText());
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_COLOR_LOCATION_BACKGROUND, String.valueOf(btnMapLocationColor.getBackground().getRGB()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_COLOR_LOCATION_BORDER, String.valueOf(btnMapLocationBorderColor.getBackground().getRGB()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LOCATION_OPACITY, String.valueOf(jsMapLocationOpacity.getValue()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LOCATION_SIZE, String.valueOf(jsMapLocationSize.getValue())); // 1 to 40
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_ADJUST_SIZE, String.valueOf(chbMapAdjustLocationSize.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_SHOW_LOCATION_INFO, String.valueOf(chbMapShowLocationInfo.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LOCATION_INFO_TYPE, String.valueOf(cmbMapLocationInfoType.getSelectedItem())); // Incidences or Time

		// tracks
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_COLOR_TRACK, String.valueOf(btnMapTrackColor.getBackground().getRGB()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_TRACK_OPACITY, String.valueOf(jsMapTrackOpacity.getValue())); // 0 to 255
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_TRACK_THICKNESS, String.valueOf(jsMapTrackThickness.getValue())); // 1 to 4

		// labels
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_DAY, String.valueOf(chbMapLabelDay.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_HOUR, String.valueOf(chbMapLabelHour.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_DISTANCE, String.valueOf(chbMapLabelDistance.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_TIME, String.valueOf(chbMapLabelTime.isSelected()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_MAP_LABEL_SHOW_SPEED, String.valueOf(chbMapLabelSpeed.isSelected()));

		// BLOCK
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_BLOCK_COLOR_NO_DATA, String.valueOf(btnBlockNoDataColor.getBackground().getRGB()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_BLOCK_COLOR_HOME, String.valueOf(btnBlockHomeColor.getBackground().getRGB()));
		PropertyUtil.setProperty(PropertyUtil.REP_GPS_BLOCK_COLOR_OUT, String.valueOf(btnBlockOutColor.getBackground().getRGB()));
	}

	public void loadDefaultOptions() {
		PropertyUtil.setDefaultGPSProperties();
		loadOptions();
	}

	public void generate() {
		try {
			sIntervalFrom.commitEdit();
			sIntervalTo.commitEdit();
		} catch (ParseException e) { /*ignored*/ }

		TreeSet<Integer> userIDs = null;
		if (!rbtUsersAll.isSelected()) {
			if (!txtUsers.hasError()) {
				userIDs = getUsers(txtUsers);
			} else {
				// show dialog with error
			}
		} else {
			// get all the subjects in the DB
			userIDs = getUsers();
		}

		if (btnTypeMap.isSelected()) {
			for (int userID = 2; userID <= 2; userID++) {
				System.out.println("\nUser: " + userID + "\n");
				userIDs.clear();
				userIDs.add(userID);

				Date begin = TimeUtil.getDate(DataUtil.dates[userID - 1][0], TimeUtil.sdfDateOnly);
				Calendar cal = Calendar.getInstance();
				cal.setTime(begin);
				cal.add(Calendar.DAY_OF_YEAR, 1);
				begin = cal.getTime();

				Date end = TimeUtil.getDate(DataUtil.dates[userID - 1][1], TimeUtil.sdfDateOnly);
				cal.setTime(end);
				cal.add(Calendar.DAY_OF_YEAR, -1);
				end = cal.getTime();

				GPSReport gpsReport = new GPSReport(
						userIDs,
						begin,
						end,
						(Date) sIntervalFrom.getValue(),
						(Date) sIntervalTo.getValue(),
						chbShowCharts.isSelected(),
						chbSaveCharts.isSelected()
				);

				gpsReport.setDailyMap(chbDailyMap.isSelected());

				gpsReport.setMapSettings(
						Integer.valueOf(txtMapHomeRadius.getText()),
						cmbMapLayer.getSelectedIndex(),
						true,
						chbMapShowMarkers.isSelected(),
						chbMapShowLocations.isSelected(),
						chbMapShowTracks.isSelected(),
						chbMapShowLabels.isSelected(),
						chbMapShowGrid.isSelected(),
						chbMapShowZoomControl.isSelected(),
						chbMapShowMarkerControl.isSelected()
				);
				gpsReport.setLocationSettings(
						Integer.valueOf(txtMapLocationRadius.getText()),
						Integer.valueOf(txtMapLocationMinTime.getText()),
						chbMapLocationMerge.isSelected(),
						Integer.valueOf(txtMapLocationMergeRadius.getText()),
						btnMapLocationColor.getBackground(),
						btnMapLocationBorderColor.getBackground(),
						jsMapLocationOpacity.getValue(),
						jsMapLocationSize.getValue(),
						chbMapShowLocationInfo.isSelected(),
						cmbMapLocationInfoType.getSelectedIndex(),
						chbMapAdjustLocationSize.isSelected()
				);
				gpsReport.setMarkerSettings(
						btnMapMarkerColor.getBackground(),
						btnMapMarkerBorderColor.getBackground(),
						jsMapMarkerOpacity.getValue(),
						chbMapLabelDay.isSelected(),
						chbMapLabelHour.isSelected(),
						chbMapLabelDistance.isSelected(),
						chbMapLabelTime.isSelected(),
						chbMapLabelSpeed.isSelected()
				);
				gpsReport.setTrackSettings(
						btnMapTrackColor.getBackground(),
						jsMapTrackThickness.getValue(),
						jsMapTrackOpacity.getValue()
				);

				gpsReport.createMaps();
			}
		}

		// TODO: Remove comment
		/*GPSReport gpsReport;
		if (!rbtPeriodAll.isSelected()) {
			gpsReport = new GPSReport(
					userIDs,
					dChooserFrom.getDate(),
					dChooserTo.getDate(),
					(Date) sIntervalFrom.getValue(),
					(Date) sIntervalTo.getValue(),
					chbShowCharts.isSelected(),
					chbSaveCharts.isSelected()
			);
		} else {
			gpsReport = new GPSReport(
					userIDs,
					(Date) sIntervalFrom.getValue(),
					(Date) sIntervalTo.getValue(),
					chbShowCharts.isSelected(),
					chbSaveCharts.isSelected()
			);
		}
		if (btnTypeMap.isSelected()) {
			gpsReport.setDailyMap(chbDailyMap.isSelected());

			gpsReport.setMapSettings(
					Integer.valueOf(txtMapHomeRadius.getText()),
					cmbMapLayer.getSelectedIndex(),
					true,
					chbMapShowMarkers.isSelected(),
					chbMapShowLocations.isSelected(),
					chbMapShowTracks.isSelected(),
					chbMapShowLabels.isSelected(),
					chbMapShowGrid.isSelected(),
					chbMapShowZoomControl.isSelected(),
					chbMapShowMarkerControl.isSelected()
			);
			gpsReport.setLocationSettings(
					Integer.valueOf(txtMapLocationRadius.getText()),
					Integer.valueOf(txtMapLocationMinTime.getText()),
					chbMapLocationMerge.isSelected(),
					Integer.valueOf(txtMapLocationMergeRadius.getText()),
					btnMapLocationColor.getBackground(),
					btnMapLocationBorderColor.getBackground(),
					jsMapLocationOpacity.getValue(),
					jsMapLocationSize.getValue(),
					chbMapShowLocationInfo.isSelected(),
					cmbMapLocationInfoType.getSelectedIndex(),
					chbMapAdjustLocationSize.isSelected()
			);
			gpsReport.setMarkerSettings(
					btnMapMarkerColor.getBackground(),
					btnMapMarkerBorderColor.getBackground(),
					jsMapMarkerOpacity.getValue(),
					chbMapLabelDay.isSelected(),
					chbMapLabelHour.isSelected(),
					chbMapLabelDistance.isSelected(),
					chbMapLabelTime.isSelected(),
					chbMapLabelSpeed.isSelected()
			);
			gpsReport.setTrackSettings(
					btnMapTrackColor.getBackground(),
					jsMapTrackThickness.getValue(),
					jsMapTrackOpacity.getValue()
			);

			gpsReport.createMaps();
		}
		else {
			// TODO: Remove comments
//			gpsReport.setBlockSettings(
//					Integer.valueOf(txtMapHomeRadius.getText()),
//					btnBlockNoDataColor.getBackground(),
//					btnBlockHomeColor.getBackground(),
//					btnBlockOutColor.getBackground()
//			);
//
//			gpsReport.createCharts();
		}*/
	}


	private void actionReloadPreview() {
		repaintBlockPreview();
	}

	protected void repaintBlockPreview() {
		pGPSPreview.setGPSValues();
		pGPSPreview.repaint();
	}


	class BlockColorChangeListener implements PropertyChangeListener {
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt.getPropertyName().equals("background")) {
				pGPSPreview.setGPSColors(new Color[]{
						btnBlockNoDataColor.getBackground(),
						btnBlockHomeColor.getBackground(),
						btnBlockOutColor.getBackground()
				});
				pGPSPreview.repaint();
			}
		}
	}


	class MapMarkerBackgroundChangeListener implements PropertyChangeListener {
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt.getPropertyName().equals("background")) {
				pMapPreview.setMarkerBackground(btnMapMarkerColor.getBackground());
				pMapPreview.repaint();
			}
		}
	}

	class MapMarkerBorderChangeListener implements PropertyChangeListener {
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt.getPropertyName().equals("background")) {
				pMapPreview.setMarkerBorderColor(btnMapMarkerBorderColor.getBackground());
				pMapPreview.repaint();
			}
		}
	}

	class MapLocationBackgroundChangeListener implements PropertyChangeListener {

		private int type; //1:Background 2:Border

		public MapLocationBackgroundChangeListener(int type) {
			this.type = type;
		}

		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt.getPropertyName().equals("background")) {
				switch (type) {
					case 1:
						pMapPreview.setLocationBackground(btnMapLocationColor.getBackground());
						pMapPreview.repaint();
						break;
					case 2:
						pMapPreview.setLocationBorderColor(btnMapLocationBorderColor.getBackground());
						pMapPreview.repaint();
						break;
				}
			}
		}
	}

	class MapLocationInfoActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			pMapPreview.setLocationInfoType(cmbMapLocationInfoType.getSelectedIndex());
			pMapPreview.repaint();
		}
	}

	class MapShowActionListener implements ActionListener {

		private int option;
		private JCheckBox checkBox;

		public MapShowActionListener(JCheckBox checkBox, int option) {
			this.option = option;
			this.checkBox = checkBox;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			pMapPreview.setShow(option, checkBox.isSelected());
			pMapPreview.repaint();
			if (option == MapPreview.LOCATION) {
				checkLocationTextField(txtMapLocationRadius);
				checkLocationTextField(txtMapLocationMinTime);
				checkLocationTextField(txtMapLocationMergeRadius);
			} else if (option >= MapPreview.LABEL_DAY) {
				setMapLabelPreviewText();
			}
		}
	}

	private void setMapLabelPreviewText() {
		String text = "";
		if (chbMapLabelDay.isSelected()) {
			text += example[0] + " - ";
		}
		if (chbMapLabelHour.isSelected()) {
			text += example[1] + " - ";
		}
		if (chbMapLabelDistance.isSelected()) {
			text += example[2] + " - ";
		}
		if (chbMapLabelTime.isSelected()) {
			text += example[3] + " - ";
		}
		if (chbMapLabelSpeed.isSelected()) {
			text += example[4] + " - ";
		}
		if (!text.equals("")) {
			text = text.substring(0, text.length() - 3);
		}

		lblMapLabelPreview.setText("e.g. " + text);
	}

	class MapLayerActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			pMapPreview.setLayerType(cmbMapLayer.getSelectedIndex());
			pMapPreview.repaint();
		}
	}

	class MapTrackColorChangeListener implements PropertyChangeListener {
		@Override
		public void propertyChange(PropertyChangeEvent evt) {
			if (evt.getPropertyName().equals("background")) {
				pMapPreview.setTrackColor(btnMapTrackColor.getBackground());
				pMapPreview.repaint();
			}
		}
	}


	class MapLocationTransparencyChangeListener implements ChangeListener {
		@Override
		public void stateChanged(ChangeEvent e) {
			jsMapLocationOpacity.setToolTipText(jsMapLocationOpacity.getValue() + "");
			pMapPreview.setLocationTransparency(jsMapLocationOpacity.getValue());
			pMapPreview.repaint();
		}
	}

	class MapLocationSizeChangeListener implements ChangeListener {
		@Override
		public void stateChanged(ChangeEvent e) {
			jsMapLocationSize.setToolTipText(jsMapLocationSize.getValue() + "");
			pMapPreview.setLocationSize(jsMapLocationSize.getValue());
			pMapPreview.repaint();
		}
	}

	class MapMarkerTransparencyChangeListener implements ChangeListener {
		@Override
		public void stateChanged(ChangeEvent e) {
			jsMapMarkerOpacity.setToolTipText(jsMapMarkerOpacity.getValue() + "");
			pMapPreview.setMarkerTransparency(jsMapMarkerOpacity.getValue());
			pMapPreview.repaint();
		}
	}

	class MapTrackTransparencyChangeListener implements ChangeListener {
		@Override
		public void stateChanged(ChangeEvent e) {
			jsMapTrackOpacity.setToolTipText(jsMapTrackOpacity.getValue() + "");
			pMapPreview.setTrackTransparency(jsMapTrackOpacity.getValue());
			pMapPreview.repaint();
		}
	}

	class MapTrackThicknessChangeListener implements ChangeListener {
		@Override
		public void stateChanged(ChangeEvent e) {
			jsMapTrackThickness.setToolTipText(jsMapTrackThickness.getValue() + "");
			pMapPreview.setTrackThickness(jsMapTrackThickness.getValue());
			pMapPreview.repaint();
		}
	}


	class LocationEmptyTextListener implements DocumentListener {
		private JNonEmptyTextField textField;

		public LocationEmptyTextListener(JNonEmptyTextField textField) {
			this.textField = textField;
		}

		@Override
		public void insertUpdate(DocumentEvent e) {
			checkText();
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			checkText();
		}

		@Override
		public void changedUpdate(DocumentEvent e) {
			checkText();
		}

		public void checkText() {
			checkLocationTextField(textField);
		}
	}

	class LocationMergeEmptyTextListener implements DocumentListener {
		private JNonEmptyTextField textField;

		public LocationMergeEmptyTextListener(JNonEmptyTextField textField) {
			this.textField = textField;
		}

		@Override
		public void insertUpdate(DocumentEvent e) {
			checkText();
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			checkText();
		}

		@Override
		public void changedUpdate(DocumentEvent e) {
			checkText();
		}

		public void checkText() {
			checkLocationMergeTextField(textField);
		}
	}


	private void checkLocationTextField(JNonEmptyTextField textField) {
		SwingUtil.checkEmptyTextField(textField, chbMapShowLocations.isSelected());
	}

	private void checkLocationMergeTextField(JNonEmptyTextField textField) {
		SwingUtil.checkEmptyTextField(textField, chbMapShowLocations.isSelected() && chbMapLocationMerge.isSelected());
	}
}
